package com.zhugy.comparecode;

import java.io.File;

import com.alibaba.fastjson.JSON;
import com.zhugy.comparecode.asm.AsmFile;
import com.zhugy.comparecode.c.CFile;
import com.zhugy.comparecode.config.CompareConfig;
import com.zhugy.comparecode.makefile.MakefileCodeFile;
import com.zhugy.comparecode.util.CommonUtils;

/**
 * 命令参数：
 * 比较单个文件：
 * {'path1':'D:\\documents\\books\\code\\osfs03-master\\a\\pmtest1.asm','path2':'D:\\documents\\books\\code\\osfs03-master\\a-z\\pmtest1.asm','type':1}
 * 比较目录：
 * {'excludeExtNames':'img|gz|zip','excludeFiles1':'bochsrc','file1ToFile2Map':'boot/include/fat12hdr.inc:boot/include/fat12hdr.asm|boot/include/load.inc:boot/include/load_inc.asm','ignoreLines1':'boot/boot.asm:24,31|boot/loader.asm:14,15,64','path1':'D:\\documents\\source\\osfs\\osfs05-master\\i\\','path2':'D:\\documents\\source\\osfs\\osfs05-master\\i-z\\','type':2}
 * 
 * @author zhuguoyin
 *
 */
public class CompareCode {


	public static void main(String[] args) {
		if (args == null || args.length < 1) {
			throw new RuntimeException("参数不正确");
		}
		
		String json = args[0];
		CompareConfig config;
		try {
			config = JSON.parseObject(json, CompareConfig.class);
		} catch (Exception e) {
			System.err.println("解析配置出错");
			e.printStackTrace();
			return;
		}
		compare(config);
	}

	private static void compare(CompareConfig config) {
		int type = config.getType();
		if (type != CompareConfig.TYPE_SINGLE_FILE && type != CompareConfig.TYPE_DIRECTORY) {
			throw new RuntimeException("参数不正确");
		}
		
		if (CommonUtils.isEmpty(config.getPath1())) {
			throw new RuntimeException("path1不能为空");
		}
		
		if (CommonUtils.isEmpty(config.getPath2())) {
			throw new RuntimeException("path2不能为空");
		}
		
		// 比较单个文件
		if (type == CompareConfig.TYPE_SINGLE_FILE) {
			boolean result = compareFile(config, "", "");
			if (result) {
				System.out.println("文件比较检查通过");
			}
		}
		
		if (type == CompareConfig.TYPE_DIRECTORY) {
			String dir1 = config.getPath1();
			String dir2 = config.getPath2();
			File f1 = new File(dir1);
			File f2 = new File(dir2);
			if (!f1.exists()) {
				throw new RuntimeException("目录1不存在：" + dir1);
			}
			if (!f1.isDirectory()) {
				throw new RuntimeException("目录1不是目录：" + dir1);
			}
			if (!f2.exists()) {
				throw new RuntimeException("目录2不存在：" + dir2);
			}
			if (!f2.isDirectory()) {
				throw new RuntimeException("目录2不是目录：" + dir2);
			}
			
			compareDirectory(config, f1, f2, "");
			
		}
	}
	
	private static boolean compareDirectory(CompareConfig config, File dir1, File dir2, String relativePath) {
		File[] fileList1 = dir1.listFiles();
		File[] fileList2 = dir2.listFiles();
		String showName = "根目录/" + relativePath;
		if (fileList1.length == 0) {
			if (fileList2.length > 0) {
				System.out.println(showName + "不匹配，左边为空，右边不为空");
				return false;
			}
			System.out.println(showName + "匹配，两边为空");
			return true;
		}
		for (File f1 : fileList1) {
			String name = f1.getName();
			String name2 = name;
			String subRelativePath = CommonUtils.isEmpty(relativePath) ? name : relativePath + "/" + name;
			if (config.isExcludeExtName(subRelativePath)) {
				System.out.println(subRelativePath + "扩展名忽略");
				continue;
			}
			
			if (config.isExcludeFile1(subRelativePath)) {
				System.out.println(subRelativePath + "在左列表中已经被排除掉，跳过");
				continue;
			}
			
			String subRelativePath2 = subRelativePath;
			if (config.hasSpecialAssign(subRelativePath)) {
				subRelativePath2 = config.getAssignComparePath(subRelativePath);
				name2 = CommonUtils.extractSimpleName(subRelativePath2);
			}
			
			if (config.isExcludeFile2(subRelativePath2)) {
				System.out.println(subRelativePath2 + "在右列表中已经被排除掉，跳过");
				continue;
			}
			
			File f2 = findInFileList(name2, fileList2);
			if (f2 == null) {
				System.err.println(subRelativePath2 + "在右边没找到");
				return false;
			}
			if (f1.isDirectory()) {
				if (!f2.isDirectory()) {
					System.out.println(showName + "/" + name + "在左边是目录，但在右边不是");
					return false;
				}
				boolean dirCompareResult = compareDirectory(config, f1, f2, subRelativePath);
				if (!dirCompareResult) {
					return false;
				} else {
					continue;
				}
			}
			if (f2.isDirectory()) {
				System.out.println(showName + "/" + name + "在左边不是目录，但在右边是");
				return false;
			}
			
			boolean equal = compareFile(config, subRelativePath, subRelativePath2);
			if (equal) {
				System.out.println(subRelativePath + "与" + subRelativePath2 + "没有差异，继续");
				continue;
			}
			System.out.println(subRelativePath + "不匹配，跳出");
			return false;
		}
		return true;
	}

	private static File findInFileList(String name, File[] fileList) {
		for (File f : fileList) {
			if (f.getName().equals(name)) {
				return f;
			}
		}
		return null;
	}

	private static boolean compareFile(CompareConfig config, String relativePath1, String relativePath2) {
		CodeFile codeFile1 = getCodeFile(config.getPath1(), relativePath1);
		CodeFile codeFile2 = getCodeFile(config.getPath2(), relativePath2);
		CompareResult cr = codeFile1.compareTo(codeFile2, config);
		if (!cr.isEquals()) {
			System.err.println(cr.getMessage());
		}
		return cr.isEquals();
	}

	private static CodeFile getCodeFile(String path, String relativePath) {
		String fullPath = CommonUtils.concatPath(path, relativePath);
		int lastIndexOfDot = fullPath.lastIndexOf(".");
		if (lastIndexOfDot < 0) {
			String simpleName = CommonUtils.extractSimpleName(fullPath);
			if ("Makefile".equalsIgnoreCase(simpleName)) {
				return new MakefileCodeFile(path, relativePath);
			}
			throw new RuntimeException("没有扩展名！！" + relativePath);
		}
		String extName = fullPath.substring(lastIndexOfDot + 1);
		extName = extName.toLowerCase();
		switch (extName) {
		case "asm":
			return new AsmFile(path, relativePath);
		case "inc":
			return new AsmFile(path, relativePath);
		case "h":
		case "c":
			return new CFile(path, relativePath);
			default:
				throw new RuntimeException("不能识别的源代码" + relativePath);
		}
	}
	
}
